const _ = require("lodash");
const router = require("koa-router")();
/**
 * api {get} /home/app/engine/function 查询云函数
 *
 * apiParam {Number} page 页码
 *
 */
router.get("/function", async (ctx, next) => {
  const baas = ctx.baas;
  const page = parseInt(ctx.query.page) < 1 ? 1 : parseInt(ctx.query.page);
  const functions = await BaaS.Models.function
    .query(qb => {
      qb.where("baas_id", "=", baas.id);
    })
    .fetchAll({ withRelated: ["class"] });
  _.map(functions, funciton => {
    return Object.assign(funciton, { type: "Function" });
  });
  const userBaas = await BaaS.Models.user_baas
    .query(qb => {
      qb.where("baas_id", "=", baas.id);
    })
    .fetch();
  const hook = await BaaS.Models.hook
    .query(qb => {
      qb.where("baas_id", "=", baas.id);
    })
    .fetchAll({ withRelated: ["class"] });
  _.map(hook, hookItem => {
    return Object.assign(hookItem, { type: "Hook" });
  });
  const global = await BaaS.Models.global
    .query(qb => {
      qb.where("baas_id", "=", baas.id);
    })
    .fetchAll({ withRelated: ["class"] });
  _.map(global, globalItem => {
    return Object.assign(globalItem, { type: "Global" });
  });
  let functionsAll = _.orderBy(
    [...functions, ...hook, ...global],
    "created_at",
    "desc"
  );
  const pagination = {
    page: page,
    pageCount: Math.ceil(functionsAll.length / ctx.config("pageSize")),
    pageSize: ctx.config("pageSize"),
    rowCount: functionsAll.length
  };
  // 手动分页
  const start = (page - 1) * ctx.config("pageSize");
  const end = start + ctx.config("pageSize");
  functionsAll = { data: _.slice(functionsAll, start, end) };
  Object.assign(
    functionsAll,
    { engine: userBaas.engine },
    { pagination: pagination }
  );
  ctx.success(functionsAll);
});
/**
 * api {get} /home/app/engine/function/:id 获取云函数信息
 *
 */
router.get("/function/:id/type/:type", async (ctx, next) => {
  const id = ctx.params.id;
  const type = ctx.params.type;
  let info = "";
  if (type == "Function") {
    info = await BaaS.Models.function
      .forge({ id: id })
      .fetch({ withRelated: ["class"] });
  } else if (type == "Hook") {
    info = await BaaS.Models.hook
      .forge({ id: id })
      .fetch({ withRelated: ["class"] });
  } else if (type == "Global") {
    info = await BaaS.Models.global
      .forge({ id: id })
      .fetch({ withRelated: ["class"] });
  } else {
    ctx.error("类型错误");
    return;
  }
  ctx.success(info);
});

/**
 * api {post} /home/app/engine/function/add 新增云函数
 *
 * apiParam {String} Id 云函数Id
 * apiParam {String} name 云函数名称
 * apiParam {String} body 云函数主体
 * apiParam {String} classId 分组id
 *
 */
router.post("/function/add", async (ctx, next) => {
  const baas = ctx.baas;
  const { id, name, body, classId, remark } = ctx.post;
  // 验证表单是否为空
  const isEmpty = ctx.isEmpty({ name: name, body: body, classId: classId }, [
    "name",
    "body",
    "classId"
  ]);
  if (!isEmpty) {
    ctx.error("请完善表单");
    return;
  }
  // 获取分组id列表，判断是否正确
  const classList = await BaaS.Models.class
    .query({ where: { baas_id: baas.id } })
    .fetchAll();
  const classIds = _.map(classList, "id");
  if (!classIds.includes(parseInt(classId))) {
    ctx.error("分组id错误");
    return;
  }
  // 查询是否存在同名函数
  const findRes = await BaaS.Models.function
    .query(qb => {
      qb.where("name", "=", name);
      qb.where("baas_id", "=", baas.id);
      qb.where("class_id", "=", classId);
    })
    .fetch();
  if (findRes && findRes.id != id) {
    ctx.error("已存在相同函数");
    return;
  }
  const key = `baas_id:${
    baas.id
  }:class_id:${classId}:name:${name}:body:${body}`;
  const locked = await BaaS.redis.lock(key);
  if (locked) {
    const addData = {
      id: id,
      baas_id: baas.id,
      class_id: classId,
      name: name,
      body: body,
      remark: remark
    };
    // 数据表添加云函数
    const result = await BaaS.Models.function.forge(addData).save({
      withRedisKey: `baas:*:appid:${baas.appid}:appkey:${
        baas.appkey
      }:class:*:function:${name}`
    });
    ctx.success(result);

    await BaaS.redis.unlock(key);
  } else {
    ctx.error("系统繁忙，请稍后重试");
    console.log(`${key} Waiting`);
    return;
  }
});
/**
 * api {post} /home/app/engine/hook/add 新增钩子
 *
 * apiParam {String} Id 钩子Id
 * apiParam {Number} classId 分组id
 * apiParam {String} table 数据表
 * apiParam {String} body 钩子主体
 * apiParam {String} remark 钩子备注
 *
 */
router.post("/hook/add", async (ctx, next) => {
  const baas = ctx.baas;
  const { id, classId, table, body, remark } = ctx.post;
  const key = `baas_id:${
    baas.id
  }:class_id:${classId}:table:${table}:body:${body}`;
  // 获取分组id列表，判断是否正确
  const classList = await BaaS.Models.class
    .query({ where: { baas_id: baas.id } })
    .fetchAll();
  const classIds = _.map(classList, "id");
  if (!classIds.includes(parseInt(classId))) {
    ctx.error("分组id错误");
    return;
  }
  // 获取数据表列表，判断表名是否正确
  const sql = `show table status from ${"`" + baas.database + "`"}`;
  const tableList = _.map((await ctx.bookshelf.knex.raw(sql))[0], "Name");
  if (table && !tableList.includes(table)) {
    ctx.error("数据表名错误");
    return;
  }
  const locked = await BaaS.redis.lock(key);
  if (locked) {
    const addData = {
      id: id,
      baas_id: baas.id,
      class_id: classId,
      table: table,
      body: body,
      remark: remark
    };
    const result = await BaaS.Models.hook.forge(addData).save({
      withRedisKey: `baas:*:appid:${baas.appid}:appkey:${
        baas.appkey
      }:class:*:table:${table}`
    });
    ctx.success(result);
    await BaaS.redis.unlock(key);
  } else {
    ctx.error("系统繁忙，请稍后重试");
    return;
  }
});
/**
 * api {post} /home/app/engine/global/add 新增全局函数
 *
 * apiParam {String} Id 钩子Id
 * apiParam {String} params 形参
 * apiParam {String} body 钩子主体
 * apiParam {String} remark 钩子备注
 *
 */
router.post("/global/add", async (ctx, next) => {
  const baas = ctx.baas;
  const { id, body, remark } = ctx.post;
  const key = `baas_id:${baas.id}:global:body:${body}`;
  const locked = await BaaS.redis.lock(key);
  if (locked) {
    const addData = {
      id: id,
      baas_id: baas.id,
      body: body,
      remark: remark
    };
    const result = await BaaS.Models.global.forge(addData).save({
      withRedisKey: `baas:*:appid:${baas.appid}:appkey:${
        baas.appkey
      }:global`
    });
    ctx.success(result);
    await BaaS.redis.unlock(key);
  } else {
    ctx.error("系统繁忙，请稍后重试");
    return;
  }
});
/**
 * api {post} /home/app/engine/function/delete 修改状态和删除
 *
 * apiParam {Number} id 云函数id
 *
 */
router.post("/function/delete", async (ctx, next) => {
  const baas = ctx.baas;
  const { id, type } = ctx.post;
  const key = `id:${id}`;
  const locked = await BaaS.redis.lock(key);
  if (locked) {
    let findRes = "";
    let deleteRes = "";
    if (type == "Function") {
      findRes = await BaaS.Models.function
        .query({ where: { id: id, baas_id: baas.id } })
        .fetch();
      deleteRes = await BaaS.Models.function
        .forge({
          id: id,
          baas_id: baas.id
        })
        .destroy({
          withRedisKey: `baas:*:appid:${baas.appid}:appkey:${
            baas.appkey
          }:class:*:function:${findRes.name}`
        });
      // 查询计划任务相关函数一并删除
      BaaS.Models.schedule
        .query(qb => {
          qb.whereIn("function_id", id);
        })
        .destroy({
          withRedisKey: `baas:*:appid:${baas.appid}:appkey:${
            baas.appkey
          }:class:*:function:${findRes.name}:schedule`
        });
    } else if (type == "Hook") {
      findRes = await BaaS.Models.hook
        .query({ where: { id: id, baas_id: baas.id } })
        .fetch();
      deleteRes = await BaaS.Models.hook
        .forge({
          id: id,
          baas_id: baas.id
        })
        .destroy({
          withRedisKey: `baas:*:appid:${baas.appid}:appkey:${
            baas.appkey
          }:class:*:table:${findRes.table}`
        });
    } else if (type == "Global") {
      findRes = await BaaS.Models.global
        .query({ where: { id: id, baas_id: baas.id } })
        .fetch();
      deleteRes = await BaaS.Models.global
        .forge({
          id: id,
          baas_id: baas.id
        })
        .destroy({
          withRedisKey: `baas:*:appid:${baas.appid}:appkey:${
            baas.appkey
          }:class:*:argv:${findRes.argv}`
        });
    }
    if (deleteRes) {
      ctx.success(deleteRes);
    } else {
      ctx.error("删除失败");
      return;
    }
    await BaaS.redis.unlock(key);
  } else {
    ctx.error("请稍后重试");
    console.log(`${key} Waiting`);
    return;
  }
});

module.exports = router;
